package org.dromara.oce.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.oce.constant.ReferralLinkType;
import org.dromara.oce.domain.OceAdvertiserEverydayCost;
import org.dromara.oce.domain.OceAdvertiserReferralRelation;
import org.dromara.oce.domain.OceEverydayCostHours;
import org.dromara.oce.domain.bo.OceAdvertiserEverydayCostBo;
import org.dromara.oce.domain.bo.OceEverydayCostHoursBo;
import org.dromara.oce.domain.dto.GetAdvertiserReportDTO;
import org.dromara.oce.domain.dto.GetHoursBlockPayAmountDTO;
import org.dromara.oce.domain.dto.GetOceEverydayCostCensusDataDTO;
import org.dromara.oce.domain.dto.GetOceEverydayHoursTotalCostDTO;
import org.dromara.oce.domain.vo.OceEverydayCostHoursVo;
import org.dromara.oce.mapper.OceAdvertiserEverydayCostMapper;
import org.dromara.oce.mapper.OceEverydayCostHoursMapper;
import org.dromara.oce.service.OceEverydayCostHoursService;
import org.dromara.oce.service.remote.OceanEngineRemoteService;
import org.dromara.oce.utils.CommonConstants;
import org.dromara.oce.utils.TimeUtils;
import org.dromara.system.domain.SysDept;
import org.dromara.system.mapper.SysDeptMapper;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 广告主消耗记录Service业务层处理
 *
 * @author Lion Li
 * @date 2024-12-24
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class OceEverydayCostHoursServiceImpl extends ServiceImpl<OceEverydayCostHoursMapper, OceEverydayCostHours> implements OceEverydayCostHoursService {

    private final OceEverydayCostHoursMapper baseMapper;
    private final SysDeptMapper deptMapper;
    private final OceAdvertiserEverydayCostMapper advertiserEverydayCostMapper;
    private final OceanEngineRemoteService engineRemoteService;

    /**
     * 查询广告主消耗记录
     *
     * @param advertiserCostId 主键
     * @return 广告主消耗记录
     */
    @Override
    public OceEverydayCostHoursVo queryById(Long advertiserCostId) {
        return baseMapper.selectVoById(advertiserCostId);
    }

    /**
     * 分页查询广告主消耗记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 广告主消耗记录分页列表
     */
    @Override
    public TableDataInfo<OceEverydayCostHoursVo> queryPageList(OceEverydayCostHoursBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
        Page<OceEverydayCostHoursVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的广告主消耗记录列表
     *
     * @param bo 查询条件
     * @return 广告主消耗记录列表
     */
    @Override
    public List<OceEverydayCostHoursVo> queryList(OceEverydayCostHoursBo bo) {
        LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OceEverydayCostHours> buildQueryWrapper(OceEverydayCostHoursBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OceEverydayCostHours> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getReferralLinkId() != null, OceEverydayCostHours::getReferralLinkId, bo.getReferralLinkId());
        lqw.eq(bo.getReferralLinkType() != null, OceEverydayCostHours::getReferralLinkType, bo.getReferralLinkType());
        lqw.eq(StringUtils.isNotBlank(bo.getThirdAdvertiserId()), OceEverydayCostHours::getThirdAdvertiserId, bo.getThirdAdvertiserId());
        lqw.like(StringUtils.isNotBlank(bo.getThirdAdvertiserName()), OceEverydayCostHours::getThirdAdvertiserName, bo.getThirdAdvertiserName());
        lqw.eq(bo.getThatdayTimestamp() != null, OceEverydayCostHours::getThatdayTimestamp, bo.getThatdayTimestamp());
        lqw.eq(StringUtils.isNotBlank(bo.getThatdayDate()), OceEverydayCostHours::getThatdayDate, bo.getThatdayDate());
        lqw.le(bo.getThatdayHoursTimestamp() != null, OceEverydayCostHours::getThatdayHoursTimestamp, bo.getThatdayHoursTimestamp());
        lqw.eq(StringUtils.isNotBlank(bo.getThatdayHoursDate()), OceEverydayCostHours::getThatdayHoursDate, bo.getThatdayHoursDate());
        lqw.eq(bo.getThatdayTotalAmount() != null, OceEverydayCostHours::getThatdayTotalAmount, bo.getThatdayTotalAmount());
        lqw.eq(bo.getThatdayDividendAmount() != null, OceEverydayCostHours::getThatdayDividendAmount, bo.getThatdayDividendAmount());
        lqw.eq(bo.getThatdayProfitAmount() != null, OceEverydayCostHours::getThatdayProfitAmount, bo.getThatdayProfitAmount());
        lqw.eq(bo.getThatdayPaidTotalNum() != null, OceEverydayCostHours::getThatdayPaidTotalNum, bo.getThatdayPaidTotalNum());
        lqw.eq(bo.getThatdayPaidUseNum() != null, OceEverydayCostHours::getThatdayPaidUseNum, bo.getThatdayPaidUseNum());
        lqw.eq(bo.getThatdayRegisterTotalAmount() != null, OceEverydayCostHours::getThatdayRegisterTotalAmount, bo.getThatdayRegisterTotalAmount());
        lqw.eq(bo.getThatdayRegisterDividendAmount() != null, OceEverydayCostHours::getThatdayRegisterDividendAmount, bo.getThatdayRegisterDividendAmount());
        lqw.eq(bo.getIaaTotalAmount() != null, OceEverydayCostHours::getIaaTotalAmount, bo.getIaaTotalAmount());
        lqw.eq(bo.getIaaDividendAmount() != null, OceEverydayCostHours::getIaaDividendAmount, bo.getIaaDividendAmount());
        lqw.eq(bo.getIaaRegisterTotalAmount() != null, OceEverydayCostHours::getIaaRegisterTotalAmount, bo.getIaaRegisterTotalAmount());
        lqw.eq(bo.getIaaRegisterDividendAmount() != null, OceEverydayCostHours::getIaaRegisterDividendAmount, bo.getIaaRegisterDividendAmount());
        lqw.eq(bo.getDramaId() != null, OceEverydayCostHours::getDramaId, bo.getDramaId());
        lqw.like(StringUtils.isNotBlank(bo.getDramaTitle()), OceEverydayCostHours::getDramaTitle, bo.getDramaTitle());
        lqw.eq(bo.getCost() != null, OceEverydayCostHours::getCost, bo.getCost());
        lqw.eq(bo.getShow() != null, OceEverydayCostHours::getShow, bo.getShow());
        lqw.eq(bo.getAvgShowCost() != null, OceEverydayCostHours::getAvgShowCost, bo.getAvgShowCost());
        lqw.eq(bo.getClick() != null, OceEverydayCostHours::getClick, bo.getClick());
        lqw.eq(bo.getAvgClickCost() != null, OceEverydayCostHours::getAvgClickCost, bo.getAvgClickCost());
        lqw.eq(bo.getCtr() != null, OceEverydayCostHours::getCtr, bo.getCtr());
        lqw.eq(bo.getConvert() != null, OceEverydayCostHours::getConvert, bo.getConvert());
        lqw.eq(bo.getConvertCost() != null, OceEverydayCostHours::getConvertCost, bo.getConvertCost());
        lqw.eq(bo.getConvertRate() != null, OceEverydayCostHours::getConvertRate, bo.getConvertRate());
        lqw.eq(bo.getActive() != null, OceEverydayCostHours::getActive, bo.getActive());
        lqw.eq(bo.getActiveCost() != null, OceEverydayCostHours::getActiveCost, bo.getActiveCost());
        lqw.eq(bo.getActiveRate() != null, OceEverydayCostHours::getActiveRate, bo.getActiveRate());
        lqw.eq(bo.getActivePay() != null, OceEverydayCostHours::getActivePay, bo.getActivePay());
        lqw.eq(bo.getActivePayCost() != null, OceEverydayCostHours::getActivePayCost, bo.getActivePayCost());
        lqw.eq(bo.getActivePayRate() != null, OceEverydayCostHours::getActivePayRate, bo.getActivePayRate());
        lqw.eq(bo.getGamePayCount() != null, OceEverydayCostHours::getGamePayCount, bo.getGamePayCount());
        lqw.eq(bo.getGamePayCost() != null, OceEverydayCostHours::getGamePayCost, bo.getGamePayCost());
        lqw.eq(bo.getCostHoursSpeed() != null, OceEverydayCostHours::getCostHoursSpeed, bo.getCostHoursSpeed());
        lqw.like(StringUtils.isNotBlank(bo.getCreateName()), OceEverydayCostHours::getCreateName, bo.getCreateName());
        lqw.eq(bo.getAppType() != null, OceEverydayCostHours::getAppType, bo.getAppType());
        lqw.eq(bo.getDividendAmountHoursCurrent() != null, OceEverydayCostHours::getDividendAmountHoursCurrent, bo.getDividendAmountHoursCurrent());
        lqw.eq(bo.getDividendAmountHoursOne() != null, OceEverydayCostHours::getDividendAmountHoursOne, bo.getDividendAmountHoursOne());
        lqw.eq(bo.getDividendAmountHoursTwo() != null, OceEverydayCostHours::getDividendAmountHoursTwo, bo.getDividendAmountHoursTwo());
        lqw.eq(bo.getDividendAmountHoursThree() != null, OceEverydayCostHours::getDividendAmountHoursThree, bo.getDividendAmountHoursThree());
        lqw.eq(bo.getDividendAmountHoursFour() != null, OceEverydayCostHours::getDividendAmountHoursFour, bo.getDividendAmountHoursFour());
        lqw.eq(bo.getDividendAmountHoursFive() != null, OceEverydayCostHours::getDividendAmountHoursFive, bo.getDividendAmountHoursFive());
        if (StringUtils.isNotBlank(bo.getStartDate()) && StringUtils.isNotBlank(bo.getEndDate())) {
            lqw.between(OceEverydayCostHours::getThatdayDate, bo.getStartDate(), bo.getEndDate());
        }
        if (Objects.nonNull(bo.getIaaFlag())) {
            if (bo.getIaaFlag().equals(CommonConstants.IAA_FLAG_NO)) {
                if (!org.dromara.common.core.utils.ObjectUtils.isEmpty(bo.getReferralLinkType()) && bo.getReferralLinkType() <= CommonConstants.REFERRAL_LINK_TYPE_DIANZHONG) {
                    lqw.eq(OceEverydayCostHours::getReferralLinkType, bo.getReferralLinkType());
                } else {
                    lqw.le(OceEverydayCostHours::getReferralLinkType, ReferralLinkType.REFERRAL_LINK_TYPE_DIANZHONG.getType());
                }
            } else {
                if (!org.dromara.common.core.utils.ObjectUtils.isEmpty(bo.getReferralLinkType()) && bo.getReferralLinkType() >= CommonConstants.REFERRAL_LINK_TYPE_FANQIE_IAA) {
                    lqw.eq(OceEverydayCostHours::getReferralLinkType, bo.getReferralLinkType());
                } else {
                    lqw.in(OceEverydayCostHours::getReferralLinkType, ReferralLinkType.REFERRAL_LINK_TYPE_FANQIE_IAA.getType(), ReferralLinkType.REFERRAL_LINK_TYPE_DAISHU_IAA.getType(),
                        ReferralLinkType.REFERRAL_LINK_TYPE_DOUYIN_ACCOUNT_IAA.getType(), ReferralLinkType.REFERRAL_LINK_TYPE_CHUAN_SHAN_JIA_IAA.getType());
                }
            }
        }
        if (bo.getDeptId() != null) {
            List<SysDept> deptList = deptMapper.selectListByParentId(bo.getDeptId());
            List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
            ids.add(bo.getDeptId());
            lqw.in(OceEverydayCostHours::getDeptId, ids);
        }
        return lqw;
    }

    /**
     * 新增广告主消耗记录
     *
     * @param bo 广告主消耗记录
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(OceEverydayCostHoursBo bo) {
        OceEverydayCostHours add = MapstructUtils.convert(bo, OceEverydayCostHours.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setAdvertiserCostId(add.getAdvertiserCostId());
        }
        return flag;
    }

    /**
     * 修改广告主消耗记录
     *
     * @param bo 广告主消耗记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(OceEverydayCostHoursBo bo) {
        OceEverydayCostHours update = MapstructUtils.convert(bo, OceEverydayCostHours.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(OceEverydayCostHours entity) {
    }

    /**
     * 校验并批量删除广告主消耗记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public void syncOceCostData(List<OceAdvertiserReferralRelation> batchList, String date, Long dateTimestamp) {
        List<OceEverydayCostHours> saveHoursList = new ArrayList<>();
        List<OceEverydayCostHours> updateHoursList = new ArrayList<>();
        List<OceAdvertiserEverydayCost> dayList = new ArrayList<>();
        List<OceAdvertiserEverydayCost> daySaveList = new ArrayList<>();
        for (OceAdvertiserReferralRelation referralRelation : batchList) {
            try {
                Long hourTimestampNow = TimeUtils.getCurrHoursTimestampSecond();
                //广告主24小时消耗数据
                List<GetAdvertiserReportDTO> advertiserReportDTOList = engineRemoteService.getAdvertiserReportHours(referralRelation.getThirdAdvertiserId(), referralRelation.getThirdAdvertiserAppCode(), date);
                if (CollectionUtils.isEmpty(advertiserReportDTOList)) {
                    continue;
                }
                // 处理当天的消耗数据
                OceAdvertiserEverydayCostBo boDay = new OceAdvertiserEverydayCostBo();
                boDay.setReferralLinkId(referralRelation.getReferralLinkId());
                boDay.setThirdAdvertiserId(referralRelation.getThirdAdvertiserId());
                boDay.setThatdayTimestamp(dateTimestamp);
                LambdaQueryWrapper<OceAdvertiserEverydayCost> lqwDay = SpringUtils.getBean(OceAdvertiserEverydayCostServiceImpl.class).buildQueryWrapper(boDay);
                //查询当天消耗数据
                OceAdvertiserEverydayCost oldDay = advertiserEverydayCostMapper.selectOne(lqwDay);
                if (Objects.isNull(oldDay)) {
                    oldDay = new OceAdvertiserEverydayCost();
                    GetAdvertiserReportDTO advertiserReport = advertiserReportDTOList.get(0);
                    BeanUtil.copyProperties(advertiserReport, oldDay);
                    BeanUtil.copyProperties(referralRelation, oldDay);
                    oldDay.setThatdayDate(date);
                    oldDay.setThatdayTimestamp(dateTimestamp);
                    //24小时数据，进行累加，得出天数据
                    oldDay = getAdvertiserDayCost(advertiserReportDTOList, oldDay);
                    oldDay.setCreateTime(LocalDateTime.now());
                    oldDay.setCreateBy("oce-server");
                    oldDay.setDeptId(referralRelation.getDeptId());
                    Optional<GetAdvertiserReportDTO> first = advertiserReportDTOList.stream().filter(item -> Objects.equals(item.getThatdayHoursTimestamp(), hourTimestampNow)).findFirst();
                    if (first.isPresent()) {
                        oldDay.setCostHoursSpeed(first.get().getCost());
                    }
                    daySaveList.add(oldDay);
                } else {
                    BeanUtil.copyProperties(referralRelation, oldDay);
                    oldDay = getAdvertiserDayCost(advertiserReportDTOList, oldDay);
                    Optional<GetAdvertiserReportDTO> first = advertiserReportDTOList.stream().filter(item -> Objects.equals(item.getThatdayHoursTimestamp(), hourTimestampNow)).findFirst();
                    if (first.isPresent()) {
                        oldDay.setCostHoursSpeed(first.get().getCost());
                    }
                    dayList.add(oldDay);
                }

                // 处理当天每小时的消耗数据
                OceEverydayCostHoursBo bo = new OceEverydayCostHoursBo();
                bo.setReferralLinkId(referralRelation.getReferralLinkId());
                bo.setThirdAdvertiserId(referralRelation.getThirdAdvertiserId());
                bo.setThatdayTimestamp(dateTimestamp);
                LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
                List<OceEverydayCostHours> oldList = baseMapper.selectJobList(lqw);//查询当天24小时数据
                for (GetAdvertiserReportDTO advertiserReportDTO : advertiserReportDTOList) {
                    // 24小时的某条时间戳
                    Long hourTimestamp = advertiserReportDTO.getThatdayHoursTimestamp();
                    // 新增数据
                    if (CollectionUtils.isEmpty(oldList)) {
                        OceEverydayCostHours everydayCostHours = new OceEverydayCostHours();
                        BeanUtil.copyProperties(advertiserReportDTO, everydayCostHours);
                        BeanUtil.copyProperties(referralRelation, everydayCostHours);
                        everydayCostHours.setThatdayDate(date);
                        everydayCostHours.setThatdayTimestamp(dateTimestamp);
                        everydayCostHours.setThatdayHoursTimestamp(hourTimestamp);
                        everydayCostHours.setThatdayHoursDate(advertiserReportDTO.getStatDatetime());
                        everydayCostHours.setReferralLinkType(referralRelation.getReferralLinkType());
                        // 计算消耗
                        everydayCostHours.computeValue();
                        everydayCostHours.computeProfitAmount();
                        everydayCostHours.computeDouYinAppAmount();
                        everydayCostHours.setCostHoursSpeed(Objects.equals(advertiserReportDTO.getThatdayHoursTimestamp(), hourTimestampNow) ? advertiserReportDTO.getCost() : BigDecimal.ZERO);
                        everydayCostHours.setCreateBy("oce-server");
                        everydayCostHours.setCreateTime(new Date());
                        everydayCostHours.setDeptId(referralRelation.getDeptId());
                        saveHoursList.add(everydayCostHours);
                    } else {// 更新数据
                        //上一小时时间戳
                        long hourLast = TimeUtils.getBeforeHoursTimestampSecond();
                        for (OceEverydayCostHours old : oldList) {
                            // 更新近2个小时的数据
                            Long oldHour = old.getThatdayHoursTimestamp();
                            if (Objects.equals(oldHour, hourTimestamp) && oldHour <= hourTimestampNow && oldHour >= hourLast) {
                                BeanUtil.copyProperties(advertiserReportDTO, old);
                                BeanUtil.copyProperties(referralRelation, old);
                                // 计算消耗
                                old.computeValue();
                                old.computeProfitAmount();
                                old.computeDouYinAppAmount();
                                if (Objects.equals(advertiserReportDTO.getThatdayHoursTimestamp(), hourTimestampNow)) {
                                    old.setCostHoursSpeed(advertiserReportDTO.getCost());
                                }
                                updateHoursList.add(old);
                                break;
                            }
                        }
                    }
                }
                if (saveHoursList.size() > 50) {
                    baseMapper.insertBatch(saveHoursList);
                    saveHoursList = new ArrayList<>();
                }
                if (updateHoursList.size() > 50) {
                    baseMapper.updateBatchById(updateHoursList);
                    updateHoursList = new ArrayList<>();
                }
                if (daySaveList.size() > 50) {
                    advertiserEverydayCostMapper.insertBatch(daySaveList);
                    dayList = new ArrayList<>();
                }
                if (dayList.size() > 50) {
                    advertiserEverydayCostMapper.updateBatchById(dayList);
                    dayList = new ArrayList<>();
                }
            } catch (Exception e) {
                log.info("更新消耗异常，{}", e);
            }
        }
        if (CollectionUtils.isNotEmpty(saveHoursList)) {
            baseMapper.insertBatch(saveHoursList);
        }
        if (CollectionUtils.isNotEmpty(updateHoursList)) {
            baseMapper.updateBatchById(updateHoursList);
        }
        if (CollectionUtils.isNotEmpty(dayList)) {
            advertiserEverydayCostMapper.updateBatchById(dayList);
        }
        if (CollectionUtils.isNotEmpty(daySaveList)) {
            advertiserEverydayCostMapper.insertBatch(daySaveList);
        }
    }

    @Override
    public GetOceEverydayCostCensusDataDTO getHourSum(OceEverydayCostHoursBo bo) {
        Integer referralLinkType = 0;
        GetOceEverydayCostCensusDataDTO totalDto = new GetOceEverydayCostCensusDataDTO();
        LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
        List<OceEverydayCostHoursVo> list = baseMapper.selectVoList(lqw);
        if (CollectionUtils.isNotEmpty(list)) {
            referralLinkType = list.get(0).getReferralLinkType();
            // 总消耗
            BigDecimal cost = list.stream().map(OceEverydayCostHoursVo::getCost).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 当日总支付笔数
            Integer thatdayPaidTotalNum = list.stream().map(OceEverydayCostHoursVo::getThatdayPaidTotalNum).filter(Objects::nonNull).reduce(0, Integer::sum);
            // 当日总收入
            BigDecimal thatdayTotalAmount = list.stream().map(OceEverydayCostHoursVo::getThatdayRegisterTotalAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 当日分成金额
            BigDecimal thatdayDividendAmount = list.stream().map(OceEverydayCostHoursVo::getThatdayRegisterDividendAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 当日利润金额=当日分成金额-当日消耗
            BigDecimal thatdayProfitAmount = list.stream().map(OceEverydayCostHoursVo::getThatdayRegisterProfitAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 当日IAA总收入
            BigDecimal iaaTotalAmount = list.stream().map(OceEverydayCostHoursVo::getIaaRegisterTotalAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            // 当日IAA分成金额
            BigDecimal iaaDividendAmount = list.stream().map(OceEverydayCostHoursVo::getIaaRegisterDividendAmount).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            totalDto.setCost(cost);
            totalDto.setThatdayPaidTotalNum(thatdayPaidTotalNum);
            totalDto.setThatdayRegisterTotalAmount(thatdayTotalAmount);
            totalDto.setThatdayRegisterProfitAmount(thatdayProfitAmount);
            totalDto.setThatdayRegisterDividendAmount(thatdayDividendAmount);
            totalDto.setIaaRegisterTotalAmount(iaaTotalAmount);
            totalDto.setIaaRegisterDividendAmount(iaaDividendAmount);
        }
        totalDto.computeRecoveryRate(referralLinkType);
        return totalDto;
    }

    @Override
    public List<GetHoursBlockPayAmountDTO> getHoursBlockPayAmount(OceEverydayCostHoursBo bo) {
        List<GetHoursBlockPayAmountDTO> dtoList = new ArrayList<>();
        PageQuery pageQuery = new PageQuery(24, 1);
        pageQuery.setOrderByColumn("thatdayHoursTimestamp");
        pageQuery.setIsAsc("desc");
        LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
        Page<OceEverydayCostHoursVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        List<OceEverydayCostHoursVo> list = result.getRecords();
        if (CollectionUtils.isNotEmpty(list)) {
            for (OceEverydayCostHoursVo record : list) {
                GetHoursBlockPayAmountDTO dto = new GetHoursBlockPayAmountDTO();
                BeanUtil.copyProperties(record, dto);
                dtoList.add(dto);
            }
        }
        return dtoList;
    }

    @Override
    public List<GetOceEverydayHoursTotalCostDTO> getOceEverydayHoursTotalCost(OceEverydayCostHoursBo bo) {
        LambdaQueryWrapper<OceEverydayCostHours> lqw = buildQueryWrapper(bo);
        List<OceEverydayCostHours> list = this.baseMapper.getOceHoursCost(lqw);
        Map<Long, GetOceEverydayHoursTotalCostDTO> map = new TreeMap<>();
        for (OceEverydayCostHours oceEverydayCostHours : list) {
            GetOceEverydayHoursTotalCostDTO data = map.get(oceEverydayCostHours.getThatdayHoursTimestamp());
            if (data == null) {
                data = new GetOceEverydayHoursTotalCostDTO();
                BeanUtil.copyProperties(oceEverydayCostHours, data);
                map.put(oceEverydayCostHours.getThatdayHoursTimestamp(), data);
            } else {
                data.setCost(data.getCost().add(oceEverydayCostHours.getCost()));
                data.setShow(data.getShow() + oceEverydayCostHours.getShow());
                if (data.getShow() != null && data.getShow() > 0) {
                    data.setAvgShowCost(NumberUtil.div(data.getCost(), data.getShow(), 5, RoundingMode.HALF_UP).scaleByPowerOfTen(3));
                }
                data.setClick(data.getClick() + oceEverydayCostHours.getClick());
                if (data.getClick() != null && data.getClick() > 0) {
                    data.setAvgClickCost(NumberUtil.div(data.getCost(), data.getClick(), 2, RoundingMode.HALF_UP));
                }
                if (data.getShow() != null && data.getShow() > 0) {
                    data.setCtr(NumberUtil.div(data.getClick(), data.getShow(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2));
                }
                data.setConvert(data.getConvert() + oceEverydayCostHours.getConvert());
                if (data.getConvert() != null && data.getConvert() > 0) {
                    data.setConvertCost(NumberUtil.div(data.getCost(), data.getConvert(), 2, RoundingMode.HALF_UP));
                }
                if (data.getClick() != null && data.getClick() > 0) {
                    data.setConvertRate(NumberUtil.div(data.getConvert(), data.getClick(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2));
                }
                data.setActive(data.getActive() + oceEverydayCostHours.getActive());
                if (data.getActive() != null && data.getActive() > 0) {
                    data.setActiveCost(NumberUtil.div(data.getCost(), data.getActive(), 2, RoundingMode.HALF_UP));
                }
                if (data.getClick() != null && data.getClick() > 0) {
                    data.setActiveRate(NumberUtil.div(data.getActive(), data.getClick(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2));
                }
                data.setActivePay(data.getActivePay() + oceEverydayCostHours.getActivePay());
                if (data.getActivePay() != null && data.getActivePay() > 0) {
                    data.setActivePayCost(NumberUtil.div(data.getCost(), data.getActivePay(), 4, RoundingMode.HALF_UP));
                }
                if (data.getActive() != null && data.getActive() > 0) {
                    data.setActivePayRate(NumberUtil.div(data.getActivePay(), data.getActive(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2));
                }
                data.setGamePayCount(data.getGamePayCount() + oceEverydayCostHours.getGamePayCount());
                if (data.getGamePayCount() != null && data.getGamePayCount() > 0) {
                    data.setGamePayCost(NumberUtil.div(data.getCost(), data.getGamePayCount(), 2, RoundingMode.HALF_UP));
                }

                data.setThatdayTotalAmount(data.getThatdayTotalAmount().add(oceEverydayCostHours.getThatdayTotalAmount()));
                data.setThatdayDividendAmount(data.getThatdayDividendAmount().add(oceEverydayCostHours.getThatdayDividendAmount()));
                data.setThatdayProfitAmount(data.getThatdayProfitAmount().add(oceEverydayCostHours.getThatdayRegisterProfitAmount()));
                data.setThatdayPaidTotalNum(data.getThatdayPaidTotalNum() + oceEverydayCostHours.getThatdayPaidTotalNum());
                data.setThatdayPaidUseNum(data.getThatdayPaidUseNum() + oceEverydayCostHours.getThatdayPaidUseNum());
                data.setDividendAmountHoursCurrent(data.getDividendAmountHoursCurrent().add(oceEverydayCostHours.getDividendAmountHoursCurrent()));
                data.setDividendAmountHoursOne(data.getDividendAmountHoursOne().add(oceEverydayCostHours.getDividendAmountHoursOne()));
                data.setDividendAmountHoursTwo(data.getDividendAmountHoursTwo().add(oceEverydayCostHours.getDividendAmountHoursTwo()));
                data.setDividendAmountHoursThree(data.getDividendAmountHoursThree().add(oceEverydayCostHours.getDividendAmountHoursThree()));
                data.setDividendAmountHoursFour(data.getDividendAmountHoursFour().add(oceEverydayCostHours.getDividendAmountHoursFour()));
                data.setDividendAmountHoursFive(data.getDividendAmountHoursFive().add(oceEverydayCostHours.getDividendAmountHoursFive()));
                data.setIaaTotalAmount(data.getIaaTotalAmount().add(oceEverydayCostHours.getIaaTotalAmount()));
                data.setIaaDividendAmount(data.getIaaDividendAmount().add(oceEverydayCostHours.getIaaDividendAmount()));
                data.setThatdayRegisterTotalAmount(data.getThatdayRegisterTotalAmount().add(oceEverydayCostHours.getThatdayRegisterTotalAmount()));
                data.setThatdayRegisterDividendAmount(data.getThatdayRegisterDividendAmount().add(oceEverydayCostHours.getThatdayRegisterDividendAmount()));
                data.setIaaRegisterTotalAmount(data.getIaaRegisterTotalAmount().add(oceEverydayCostHours.getIaaRegisterTotalAmount()));
                data.setIaaRegisterDividendAmount(data.getIaaRegisterDividendAmount().add(oceEverydayCostHours.getIaaRegisterDividendAmount()));

                BigDecimal returnRate = data.getThatdayPaidUseNum() == 0 ? BigDecimal.ZERO : new BigDecimal(data.getConvert()).divide(new BigDecimal(data.getThatdayPaidUseNum()), 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
                data.setReturnRate(returnRate);
                try {
                    BigDecimal costTemp = data.getCost();
                    if (NumberUtil.equals(data.getCost(), BigDecimal.ZERO)) {
                        costTemp = new BigDecimal("1");
                    }else{
//                        costTemp = cost.divide(new BigDecimal("1.015"), 4, RoundingMode.HALF_UP);
                    }
                    BigDecimal extRecoveryRate = BigDecimal.ZERO;
                    if (CommonConstants.IAA_FLAG_NO.equals(bo.getIaaFlag())) {
                        extRecoveryRate = data.getThatdayRegisterDividendAmount().divide(costTemp, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
                    } else if (CommonConstants.IAA_FLAG_YES.equals(bo.getIaaFlag())) {
                        extRecoveryRate = (data.getIaaRegisterDividendAmount().add(data.getThatdayRegisterDividendAmount())).divide(costTemp, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
                    }
                    data.setExtRecoveryRate(extRecoveryRate);
                } catch (Exception e) {
                    log.info("回本率计算异常，{}", e);
                }

                try {
                    BigDecimal extAvgPrice = BigDecimal.ZERO;
                    if (CommonConstants.IAA_FLAG_NO.equals(bo.getIaaFlag())) {
                        if (!ObjectUtils.isEmpty(data.getThatdayPaidUseNum()) && data.getThatdayPaidUseNum() > 0) {
                            extAvgPrice = data.getThatdayDividendAmount().divide(new BigDecimal(data.getThatdayPaidUseNum()), 2, RoundingMode.HALF_UP);
                        }
                    } else if (CommonConstants.IAA_FLAG_YES.equals(bo.getIaaFlag())) {
                        if (!ObjectUtils.isEmpty(data.getConvert()) && data.getConvert() > 0) {
                            extAvgPrice = data.getIaaDividendAmount().divide(new BigDecimal(data.getConvert()), 2, RoundingMode.HALF_UP);
                        }
                    }
                    data.setExtAvgPrice(extAvgPrice);
                } catch (Exception e) {
                    log.info("客单价计算异常，{}", e);
                }

                try {
                    BigDecimal extPayCost = BigDecimal.ZERO;
                    if (CommonConstants.IAA_FLAG_NO.equals(bo.getIaaFlag())) {
                        if (!ObjectUtils.isEmpty(data.getThatdayPaidUseNum())) {
                            Integer thatdayPaidUseNum2 = data.getThatdayPaidUseNum();
                            if (data.getThatdayPaidUseNum() == 0) {
                                thatdayPaidUseNum2 = 1;
                            }
                            extPayCost = data.getCost().divide(new BigDecimal(thatdayPaidUseNum2), 2, RoundingMode.HALF_UP);
                        }
                    } else if (CommonConstants.IAA_FLAG_YES.equals(bo.getIaaFlag())) {
                        if (!ObjectUtils.isEmpty(data.getActive())) {
                            Integer active = data.getActive();
                            if (data.getActive() == 0) {
                                active = 1;
                            }
                            extPayCost = data.getCost().divide(new BigDecimal(active), 2, RoundingMode.HALF_UP);
                        }
                    }
                    data.setExtPayCost(extPayCost);
                } catch (Exception e) {
                    log.info("付费成本计算异常，{}", e);
                }
                map.put(oceEverydayCostHours.getThatdayHoursTimestamp(), data);
            }
        }

        List<GetOceEverydayHoursTotalCostDTO> respList = new ArrayList<>();
        for (Map.Entry<Long, GetOceEverydayHoursTotalCostDTO> entry : map.entrySet()) {
            respList.add(entry.getValue());
        }
        Collections.reverse(respList);
        map = null;
        return respList;
    }

    /**
     * 合计24条小时数据为一条
     *
     * @param advertiserReportDTOList
     * @param oceAdvertiserEverydayCost
     * @return
     */
    public OceAdvertiserEverydayCost getAdvertiserDayCost(List<GetAdvertiserReportDTO> advertiserReportDTOList, OceAdvertiserEverydayCost oceAdvertiserEverydayCost) {
        OceAdvertiserEverydayCost everydayCost = new OceAdvertiserEverydayCost();
        for (GetAdvertiserReportDTO dto : advertiserReportDTOList) {
            everydayCost.setCost(everydayCost.getCost().add(dto.getCost()));
            everydayCost.setShow(everydayCost.getShow() + dto.getShow());
            everydayCost.setClick(everydayCost.getClick() + dto.getClick());
            everydayCost.setConvert(everydayCost.getConvert() + dto.getConvert());
            everydayCost.setActive(everydayCost.getActive() + dto.getActive());
            everydayCost.setActivePay(everydayCost.getActivePay() + dto.getPayCount());
            everydayCost.setGamePayCount(everydayCost.getGamePayCount() + dto.getGamePayCount());
            everydayCost.setAttributionMicroGame0dLtv(everydayCost.getAttributionMicroGame0dLtv().add(dto.getAttributionMicroGame0dLtv()));
        }
        // 平均千次展现费用=总花费/展示数*1000
        BigDecimal avgShowCost = everydayCost.getShow() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getShow(), 5, RoundingMode.HALF_UP).scaleByPowerOfTen(3);
        // 平均点击单价=总花费/点击数
        BigDecimal avgClickCost = everydayCost.getClick() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getClick(), 2, RoundingMode.HALF_UP);
        // 点击率=点击数/展示数*100%
        BigDecimal ctr = everydayCost.getShow() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getClick(), everydayCost.getShow(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2);
        // 转化成本
        BigDecimal convertCost = everydayCost.getConvert() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getConvert(), 2, RoundingMode.HALF_UP);
        // 转化率=转化数/点击数*100%
        BigDecimal convertRate = everydayCost.getClick() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getConvert(), everydayCost.getClick(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2);
        // 激活成本=总消耗/激活数
        BigDecimal activeCost = everydayCost.getActive() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getActive(), 2, RoundingMode.HALF_UP);
        // 激活率=激活数/点击数*100%
        BigDecimal activeRate = everydayCost.getClick() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getActive(), everydayCost.getClick(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2);
        // 首次付费成本=消耗/付费次数
        BigDecimal activePayCost = everydayCost.getActivePay() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getActivePay(), 4, RoundingMode.HALF_UP);
        // 首次付费率=首次付费数/激活数
        BigDecimal activePayRate = everydayCost.getActive() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getActivePay(), everydayCost.getActive(), 4, RoundingMode.HALF_UP).scaleByPowerOfTen(2);
        // 付费成本=消耗/付费次数
        BigDecimal gamePayCost = everydayCost.getGamePayCount() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getCost(), everydayCost.getGamePayCount(), 2, RoundingMode.HALF_UP);

        BigDecimal attributionMicroGame0dRoi = everydayCost.getCost().doubleValue() == 0 ? BigDecimal.ZERO : NumberUtil.div(everydayCost.getAttributionMicroGame0dLtv(), everydayCost.getCost(), 2, RoundingMode.HALF_UP);

        oceAdvertiserEverydayCost.setCost(everydayCost.getCost());
        oceAdvertiserEverydayCost.setShow(everydayCost.getShow());
        oceAdvertiserEverydayCost.setAvgShowCost(avgShowCost);
        oceAdvertiserEverydayCost.setClick(everydayCost.getClick());
        oceAdvertiserEverydayCost.setAvgClickCost(avgClickCost);
        oceAdvertiserEverydayCost.setCtr(ctr);
        oceAdvertiserEverydayCost.setConvert(everydayCost.getConvert());
        oceAdvertiserEverydayCost.setConvertCost(convertCost);
        oceAdvertiserEverydayCost.setConvertRate(convertRate);
        oceAdvertiserEverydayCost.setActive(everydayCost.getActive());
        oceAdvertiserEverydayCost.setActiveCost(activeCost);
        oceAdvertiserEverydayCost.setActiveRate(activeRate);
        oceAdvertiserEverydayCost.setActivePay(everydayCost.getActivePay());
        oceAdvertiserEverydayCost.setGamePayCount(everydayCost.getGamePayCount());
        oceAdvertiserEverydayCost.setGamePayCost(gamePayCost);
        oceAdvertiserEverydayCost.setActivePayCost(activePayCost);
        oceAdvertiserEverydayCost.setActivePayRate(activePayRate);
        oceAdvertiserEverydayCost.setGamePayCost(gamePayCost);
        oceAdvertiserEverydayCost.setAttributionMicroGame0dRoi(attributionMicroGame0dRoi);
        oceAdvertiserEverydayCost.setAttributionMicroGame0dLtv(everydayCost.getAttributionMicroGame0dLtv());
        oceAdvertiserEverydayCost.computeDouYinAppAmount();
        oceAdvertiserEverydayCost.computeProfitAmount();
        oceAdvertiserEverydayCost.computeRateValue();
        return oceAdvertiserEverydayCost;
    }

}
